 #include "analysis.h"
#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QHostInfo>
#include <QMessageBox>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    modbus_init();
}

MainWindow::~MainWindow()
{
    delete ui;
}

//字节数组转16进制字符串
void ByteToHexString(QString &str, QByteArray &ba)
{
    QString strs = ba.toHex().toUpper();//直接转换中间没有空格
    qDebug() << ba.toHex() << endl;
    for(int i=0;i<strs.length();i+=2)
    {
        QString str_1 = strs.mid (i,2);
        str += str_1;
        str += " ";
    }
}

//byte数组转hexstring
QString HexByteArrayToHexString(QByteArray HexByteArr,int ConvertLen, int pattern = 0)
{
    //获得目标数组大小
    int HexByteArrSize = HexByteArr.size();
    //判断长度是否合法，如果长度大于数组长度，则设为数组长度，小于0则设置为0
    if(ConvertLen > HexByteArrSize)
    {
        ConvertLen = HexByteArrSize;
    }
    else if(ConvertLen < 0)
    {
        ConvertLen = 0;
    }
    //声明目标字符串
    QString readMes = NULL;

    for(int i = 0; i < ConvertLen; i++)
    {
        readMes += QString("%1").arg((quint8)HexByteArr.at(i),2,16,QLatin1Char('0'));
        //判断转换的模式
        if(pattern == 1)
        {
            readMes += " ";
        }
    }
    //返回转化后的十六进制字符串
    return readMes;
}


//主线程初始化
void MainWindow::modbus_init()
{
    qDebug()<<"主线程初始化";

    MyServer = new QTcpServer(this);

    //显示当前时间
    m_timer = new QTimer(this);
    connect(m_timer, SIGNAL(timeout()), this, SLOT(showtime()));
    m_timer->setInterval(1000);
    m_timer->start();

    //表格初始化
    readseting = new QSettings("Data.ini", QSettings::IniFormat);
    table_dataInit();
    //将ini文件放入到表格中
    m_analysis = new analysis;

    //信号连接
    connect(m_analysis,&analysis::toUishowMsg,this,&MainWindow::ShowMsgString,Qt::QueuedConnection);
    connect(m_analysis,&analysis::toUishowMsgPack,this,&MainWindow::ShowMsgQByteArray,Qt::QueuedConnection);
    connect(m_analysis,&analysis::analysis_over,this,&MainWindow::sendBackMsg,Qt::QueuedConnection);
    connect(m_analysis,&analysis::wirtTablec,this,&MainWindow::wirtTablec,Qt::QueuedConnection);
    connect(m_analysis,&analysis::wirtTabler,this,&MainWindow::wirtTabler,Qt::QueuedConnection);
    connect(this,&MainWindow::Start,m_analysis,&analysis::receiveModbus,Qt::QueuedConnection);

    connect(ui->listen_btn,&QPushButton::clicked,this,&MainWindow::ListenTcpServer);
    connect(ui->refresh_ip,&QPushButton::clicked,[=](){ui->ip_Edit->setText(getLocalIp());});

    //限制从机地址
    connect(ui->addr,&QLineEdit::textChanged,[=](){
        if(ui->addr->text().toInt()>247||ui->addr->text().toInt()<1)
        {
            QMessageBox::warning(this,"提示","请检查从机地址是否合法！",QMessageBox::Ok,QMessageBox::NoButton);
            ui->addr->text().clear();
        }
    });


    //显示新建连接
    connect(MyServer,&QTcpServer::newConnection,[&](){
        //连接提示
        CreateNewConnect();
        //接收到数据
        connect(MySocket,&QTcpSocket::readyRead,this,[=](){
                //显示接收数据
                //ShowRequest();
                ShowRequest();
                m_addr = (quint8)ui->addr->text().toInt();
                emit Start(ba,m_addr);
                ba.clear();
        });
        //客户端断开提示
        connect(MySocket,static_cast<void(QAbstractSocket::*)(QAbstractSocket::SocketError)>(&QAbstractSocket::error),
                [&](QAbstractSocket::SocketError socketError){ShowTcpServerDisconnect(socketError);}
        );

    });
    ipDefalut();
    SlaveAddressDefault();
    ReadOutIniData();
}

//表格初始化
void MainWindow::table_dataInit()
{
    //设置表格
    QStringList TableHeader;
    TableHeader << "地址" << "数据";
    ui->table_coil->setVerticalHeaderLabels(TableHeader);
    ui->table_coil->setSelectionMode(QAbstractItemView::SingleSelection);
    ui->tableregs->setVerticalHeaderLabels(TableHeader);
    ui->tableregs->setSelectionMode(QAbstractItemView::SingleSelection);
    ui->tableregs->setEditTriggers(QAbstractItemView::NoEditTriggers);
    ui->table_coil->setEditTriggers(QAbstractItemView::NoEditTriggers);
}





//将ini文件中的数据放到对应的表格中
void MainWindow::ReadOutIniData(void)
{
    for(int i = 0; i < (65535 + 1); i++)
    {
        //地址设置
        QString adr =  "0X" + QString("%1").arg(i,4,16,QLatin1Char('0'));
        ui->table_coil->setItem(0,i, new QTableWidgetItem(QString(adr).toUpper()));
        ui->table_coil->item(0,i)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
        ui->tableregs->setItem(0,i, new QTableWidgetItem(QString(adr)));
        ui->tableregs->item(0,i)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
        //读出线圈数据
        QString coilData = readseting->value("Section" + QString::number(i+1) + "/coil").toString();
        //读出寄存器数据
        QString registerData = readseting->value("Section" + QString::number(i+1) + "/regi").toString();
        //在线圈数据表中显示数据
        ui->table_coil->setItem(1,i,new QTableWidgetItem(coilData));
        //设置表格内文字水平+垂直对齐
        ui->table_coil->item(1,i)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
        //在寄存器数据表中显示数据
        ui->tableregs->setItem(1,i,new QTableWidgetItem(registerData));
        //设置表格内文字水平+垂直对齐
        ui->tableregs->item(1,i)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
    }
}

//更新寄存器表
void MainWindow::wirtTabler(quint16 num, quint16 satrtaddr,QVector<quint16> bar)
{
    ui->tableregs->blockSignals(true);
    for(int i = satrtaddr,k=0; k < num;k++,i++)
    {
      ui->tableregs->setItem(1,i,new QTableWidgetItem(QString("%1").arg(bar[k])));
      ui->tableregs->item(1,i)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
    }
    ui->tableregs->blockSignals(false);
    bar.clear();
}

//更新线圈表
void MainWindow::wirtTablec(quint16 num, quint16 satrtaddr,QString bac)
{
    ui->table_coil->blockSignals(true);
    for(int i = satrtaddr,k=0; k < num;k++,i++)
    {
        //在线圈数据表中显示数据
        QString data;
        if(bac[k] == '1')
        {
            data ="1";
        }
        else
        {
            data ="0";
        }
        ui->table_coil->setItem(1,i,new QTableWidgetItem(data));
        ui->table_coil->item(1,i)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
    }
    ui->table_coil->blockSignals(false);
    bac.clear();
}

//显示时间
void MainWindow::showtime()
{
    QDateTime date_time = QDateTime::currentDateTime();
    QString time = date_time.toString("yyyy.MM.dd hh:mm:ss ddd");
    ui->timeshow->setText(time);
}
//显示主站的报文
void MainWindow::ShowMsgArray(QByteArray ba)
{
    QString str;
    ByteToHexString(str,ba);
    ui->show_Edit->append("回应报文\r\n"+str);
    ui->show_Edit->moveCursor(QTextCursor::End);
}
//显示异常信息
void MainWindow::ShowMsgErro(QString str)
{
    ui->show_Edit->append(str);
    ui->show_Edit->moveCursor(QTextCursor::End);
}
//接收数据

//清除消息接收框
void MainWindow::on_pushButton_clicked()
{
    ui->show_Edit->clear();
}
//历史文件保存
void MainWindow::on_save_btn_clicked()
{
    QString fileName=QFileDialog::getSaveFileName(this,"Save File",QDir::currentPath());
    if(fileName.isEmpty())
       {
           QMessageBox::information(this,"Error Message","请选择文件的路径");
           return;
       }
      QFile *file=new QFile;
      file->setFileName(fileName);
         bool ok=file->open(QIODevice::WriteOnly);
         if(ok)
         {
             QTextStream out(file);
             out<<ui->show_Edit->toPlainText();
             file->close();
             delete file;
         }
         else
           {
               QMessageBox::information(this,"Error Messaage","File Save Error"+file->errorString());
               return;
         }
}


//文件传输槽函数
void MainWindow::fileStart()
{

}



//建立连接
void MainWindow::creatConnect()
{
      TcpServerConnectState =true;
      //获取套接字和标识符
      MySocket=MyServer->nextPendingConnection();
      MySocket->setSocketOption(QAbstractSocket::LowDelayOption,0);

       tcpReceiveSocketDescriptor = MySocket->socketDescriptor();
       //获取客户端IP
       ClientIpAddress = MySocket->peerAddress().toString();
       //获取客户端 端口
       ClientPortNumber = MySocket->peerPort();

       AddTime();
       ui->show_Edit->append("新建连接："+ClientIpAddress+":"+QString::number(ClientPortNumber));
}
//连接断开信息提示
void MainWindow::DisconnectShowMsg()
{
    TcpServerConnectState = false;
    AddTime();
    ui->show_Edit->append("断开连接："+ClientIpAddress+":"+QString::number(ClientPortNumber));
}
//16进制数组转成字符串
void MainWindow::ResponseMsg(QByteArray ba)
{
    QString str;
    str =HexByteArrayToHexString(ba,ba.size(),1);
    ui->show_Edit->append("响应报文为："+str);
}

//显示请求报文
void MainWindow::ShowRequest()
{
    QString res;
    ba = MySocket->readAll();
    res = HexByteArrayToHexString(ba,ba.size(),1);
    AddTime();
    ui->show_Edit->append("请求报文内容："+res);
}

//显示时间戳
void MainWindow::AddTime()
{
    QDateTime current_date_time =QDateTime::currentDateTime();
    QString current_date =current_date_time.toString("yyyy.MM.dd hh:mm:ss");
    ui->show_Edit->append(current_date );
}


//判断
bool MainWindow::AskMessage(QString msg)
{
    QMessageBox::StandardButton close;
    close = QMessageBox::question(this,"提示",msg,QMessageBox::Yes | QMessageBox::No,QMessageBox::No);

    if(close==QMessageBox::Yes)
    {
        return true;
    }
    else {
        return false;
    }
}

//显示异常信息
void MainWindow::ShowMsgString(QString error)
{
    ui->show_Edit->append(error);
    ui->show_Edit->moveCursor(QTextCursor::End);
}

//显示回应报文
void MainWindow::ShowMsgQByteArray(QByteArray ba)
{
    QString str;
    ByteToHexString(str,ba);
    ui->show_Edit->append("回应报文\r\n"+str);
    ui->show_Edit->moveCursor(QTextCursor::End);
}

//初始化ip地址
void MainWindow::ipDefalut()
{
    if(ui->ip_Edit->text().isEmpty())
    {
        ipAddress =defaultIPAddress;
        ui->ip_Edit->setText(ipAddress);
    }
}

QString MainWindow::getLocalIp()
{
    QString hostName=QHostInfo::localHostName();            //本地主机名
    QHostInfo hostInfo=QHostInfo::fromName(hostName);      //本机IP地址
    QList<QHostAddress> addList=hostInfo.addresses();      //IP地址列表
     for (int i=0;i<addList.count();i++)
     {
         QHostAddress aHost=addList.at(i); //每一项是一个QHostAddress
         if(QAbstractSocket::IPv4Protocol==aHost.protocol())
         {
             return aHost.toString(); //显示出Ip地址
         }
     }
     return defaultIPAddress;
}

//初始化从机地址
void MainWindow::SlaveAddressDefault()
{
    if(ui->addr->text().isEmpty())
    {
        SlaveAddress = defaultSlaveAddress;
        ui->addr->setText(QString::number(SlaveAddress));
    }
}

//监听

void MainWindow::ListenTcpServer()
{
    //对端口建立监听
    if(ui->listen_btn->text() == "开始监听")
    {
        //当前端口正在监听
        if(MyServer->isListening())
        {
            //关闭当前端口监听
            MyServer->close();
        }

        //获取输入框内ip地址、端口号、从机地址
        //判断ip地址是否为空
        if(ui->ip_Edit->text().isEmpty())
        {
            ipAddress = defaultIPAddress;
            ui->show_Edit->append("ip地址为空，使用默认ip地址："+ipAddress);
        }
        else
        {
           //ip地址不为空，判断ip是否合法
           bool ipAddressIsLegal;
           QHostAddress ip(ui->ip_Edit->text());
           ip.toIPv4Address(&ipAddressIsLegal);
           if(!ipAddressIsLegal)
           {
               ipAddress = defaultIPAddress;
               ui->show_Edit->append("ip地址非法，使用默认ip地址："+ipAddress);
           }
           else
           {
               ipAddress = ui->ip_Edit->text();
           }
        }

        //判断端口是否为空
        if(ui->port_lineEdit->text().isEmpty())
        {
            portNum = 502;
            ui->show_Edit->append("端口号为空，使用默认端口号："+QString::number(portNum));
        }
        else
        {
            //端口不为空
            //判断端口是否合法
            bool PortNumberIsLegal;
            portNum = ui->port_lineEdit->text().toUShort(&PortNumberIsLegal,10);
            if(!PortNumberIsLegal)
            {
                ui->show_Edit->append("端口号非法，使用默认端口号："+QString::number(502));
                portNum = 502;
            }
        }

        //判断从机地址是否为空
        if(ui->addr->text().isEmpty())
        {
            SlaveAddress = defaultSlaveAddress;
            ui->show_Edit->append("从机地址为空，使用默认从机地址："+QString::number(SlaveAddress));
        }
        else
        {
            SlaveAddress = ui->addr->text().toInt();
        }

        //监听
        isConnect = MyServer->listen(QHostAddress(ipAddress),portNum);
        if(!isConnect)
        {
            QMessageBox::warning(this,"错误",MyServer->errorString());
            MyServer->close();
            return;
        }

        ui->ip_Edit->setEnabled(false);
        ui->port_lineEdit->setEnabled(false);
        ui->addr->setEnabled(false);

        ui->show_Edit->append("开始监听："+ipAddress+":"+QString::number(portNum));
        ui->show_Edit->append("从机地址："+QString::number(SlaveAddress));
        ui->listen_btn->setText("停止监听");
    }
    else if(ui->listen_btn->text() == "停止监听")
    {
        MyServer->close();
        isConnect = false;
        ui->show_Edit->append("停止监听："+ipAddress+":"+QString::number(portNum));
        ui->listen_btn->setText("开始监听");
        ui->ip_Edit->setEnabled(true);
        ui->port_lineEdit->setEnabled(true);
        ui->addr->setEnabled(true);
        ui->refresh_ip->setEnabled(true);

        //停止监听端口时，关闭所有连接
        if(1 == TcpServerConnectState)
        {
            //关闭连接
            MySocket->close();
            TcpServerConnectState = false;
            ui->show_Edit->append("断开连接："+MasterIpAddress+":"+QString::number(MasterPortNumber));
        }
    }
    else
    {
        isConnect = false;
        ui->show_Edit->append("监听失败，请重试！");
        ui->show_Edit->append("无法监听："+ipAddress+":"+QString::number(portNum));
        ui->listen_btn->setText("连接");
    }
}
//建立新连接

void MainWindow::CreateNewConnect()
{
    TcpServerConnectState = true;
    //获取套接字及其标识符
    MySocket = MyServer->nextPendingConnection();
    MySocket->setSocketOption(QAbstractSocket::LowDelayOption,0);

    tcpReceiveSocketDescriptor = MySocket->socketDescriptor();
    //获取客户端IP
    MasterIpAddress = MySocket->peerAddress().toString();
    //获取客户端接口
    MasterPortNumber = MySocket->peerPort();
    //显示客户端连接信息
    ui->show_Edit->append("新建连接："+MasterIpAddress+":"+QString::number(MasterPortNumber));
}


void MainWindow::sendBackMsg(QByteArray msg)
{
    MySocket->write(msg);
}


void MainWindow::ShowTcpServerDisconnect(QAbstractSocket::SocketError)
{
    TcpServerConnectState = false;
//    TimeInformation();
    ui->show_Edit->append("断开连接："+MasterIpAddress+":"+QString::number(MasterPortNumber));
}


/*传输文件槽函数*/
void MainWindow::on_Transfiles_clicked()
{
    widget = new Widget();
    widget->show();
}
